namespace PatterTest {
	type inferTest<T> = T extends Promise<infer M> ? M : never;

	type demoType = inferTest<Promise<123>>;

	type strType = inferTest<Promise<string>>;

	type arr = [123, "abc", string, 444, "haha"];

	// 数组的 First ， Last, PoPArr , ShiftArr
	// First 获取数组第一个数个值的类型

	type First<T extends unknown[]> = T extends [infer F, ...unknown[]]
		? F
		: never;

	type first = First<arr>; // 123

	// Last 获取数组最后一个数值的类型
	//

	type Last<Arr extends unknown[]> = Arr extends [...unknown[], infer L]
		? L
		: never;

	type last = Last<arr>; // 123

	// PoPArr 删除数组最后一个元素剩下的类型

	type PoPArr<T extends unknown[]> = T extends [...infer R, unknown]
		? R
		: never;

	type popOthersType = PoPArr<arr>;

	// ShiftArr 删除数组第一个元素剩下的类型

	type ShiftArr<T extends unknown[]> = T extends [unknown, ...infer L]
		? L
		: never;

	type shiftOthersType = ShiftArr<arr>;

	// 字符串配置
	// StartWith 传两个字符串，实现判断第一个字符串是否以第二个字符串开头

	type StartWith<S extends string, E extends string> = S extends `${E}${string}`
		? true
		: false;

	type isStart = StartWith<"my book", "my">; // true

	type isNotStart = StartWith<"my books", "book">; // false

	// 实现 ReplaceStr 传递三个字符串，实现字符串的replace功能

	type ReplaceStr<
		A extends string,
		S extends string,
		R extends string,
	> = A extends `${infer Start}${S}${infer End}` ? `${Start}${R}${End}` : A;

	type replaceStr1 = ReplaceStr<
		"my name is ? and my habbit is reading",
		"?",
		"yuanyuan"
	>; // my name is yuanyuan and my habbit is reading

	type replaceStr2 = ReplaceStr<"zyy", "?", "yuanyuan">; // zyy

	// 实现字符串的Trim 功能；

	type LeftTrim<T extends string> = T extends ""
		? ""
		: T extends `${" " | "\t"}${infer Arg}`
			? LeftTrim<Arg>
			: T;

	type RightTrim<T extends string> = T extends ""
		? ""
		: T extends `${infer Arg}${" " | "\t"}`
			? RightTrim<Arg>
			: T;

	type Trim<T extends string> = LeftTrim<RightTrim<T>>;

	type myTrimString = Trim<" abc    ">; // abc

	type NumStr = Trim<"   ">;
	type NumStr2 = Trim<"">;

	// 函数参数相关

	type GetFuncParams<Fun extends Function> = Fun extends (
		...arg: infer Arg
	) => unknown
		? Arg
		: never;

	type argsType = GetFuncParams<(name: string, age: number) => string>; // 希望得到这样的数据 [name: string, age: number]
	type argsType2 = GetFuncParams<() => string>; // 希望得到这样的数据 [name: string, age: number]

	// 得到函数返回值类型

	type FunReturnType<Fun extends Function> = Fun extends (
		...arg: any[]
	) => infer R
		? R
		: never;

	type Func1ReturnType = FunReturnType<
		(name: string, age: number) => { name: string; pageSize: number }
	>;

	// class 中的this指向的问题； 有时候我们不希望class创建的方法this的指向发生变化
	// 因为在不经意间我们会修改这里的this的指向

	class SupPerson {
		name: string;
		age: number;

		constructor(name: string, age: number) {
			this.name = name;
			this.age = age;
		}

		sayHi(this: SupPerson) {
			console.log("i say", this.name, "old", this.age);
		}
	}

	const p = new SupPerson("zhangsan", 18);

	p.sayHi();

	// 下面的代码就报错了, 这里要把 strictBindCallApply 打开
	// p.sayHi.call({
	// 	name: "dog",
	// 	age: 10,
	// });

	// 这里是获取 sayHi this的指向
	type GetSayHiThisType<Func extends Function> = Func extends (
		this: infer T,
		...arg: any[]
	) => unknown
		? T
		: never;

	type thisType = GetSayHiThisType<typeof p.sayHi>;

	// 对构造器的处理
	interface Person {
		name: string;
	}

	interface PersonConstructor {
		new (name: string, age: number): Person;
	}

	// GetConstructorParams 获取构建函数的参数类型列表

	type GetConstructorParams<
		T extends {
			new (...arg: any[]): any;
		},
	> = T extends {
		new (...arg: infer Arg): any;
	}
		? Arg
		: never;

	type constructorArgTypes = GetConstructorParams<PersonConstructor>;

	// GetConstructorReturnType 获取构建函数的返回值类型

	type GetConstructorReturnType<
		T extends {
			new (...arg: any[]): any;
		},
	> = T extends {
		new (...arg: any[]): infer R;
	}
		? R
		: never;

	type getConsReturnType = GetConstructorReturnType<PersonConstructor>;

	// 处理索引类型

	const ref1 = {
		name: "hahah",
	};

	const ref2 = {
		ref: 123,
	};

	type refTypeDemo = {
		ref?: string;
	};

	type refTypeDemo2 = {
    name: string
	};

	// 我希望得到 ref1,ref2 中的 ref 是什么类型
	//

	type GetRefType<RefObj> = `ref` extends keyof RefObj
		? RefObj["ref"]
		: undefined;

	type GetRefTypeStand<RefObj> = `ref` extends keyof RefObj
		? RefObj extends { ref?: infer Value | undefined }
			? Value
			: undefined
		: undefined;

	type refType1 = GetRefType<typeof ref1>;

	type refType2 = GetRefType<typeof ref2>;

	type ref22 = GetRefType<refTypeDemo>;

  type ref33 = GetRefTypeStand<refTypeDemo2>
}
